
#include <BPainter>
#include <BMouseEvent>

#include "PixmapArea.h"
#include "LayerDragger.h"

LayerDragger::LayerDragger() : Operation("LayerDragger")
{
	_dragPart = Part_None;
	_dirtySelection = false;

}
LayerDragger::~LayerDragger()
{

}

void LayerDragger::applyPartDraging(const BPoint& pos)
{
	BPoint offset = pos - _dragPoint;
	BRect initRect = _dragRectMap[Part_None];
	PixmapArea* pixmapArea = this->pixmapArea();
	BWidgetSet selectedWidgets = pixmapArea->selectedWidgets();
	BRect area = pixmapArea->area();
	int zoom = pixmapArea->zoom();
	if (_dragPart == Part_Center)
	{
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect += offset;
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Left)
	{
		BRect rect = initRect;
		rect.left() = rect.left() + offset.x();
		BPoint origin = (initRect.rightCenter() - area.pos()) * 100.0 / zoom;
		double ratio = (double)rect.width() / initRect.width();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, ratio, 1.0);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Top)
	{
		BRect rect = initRect;
		rect.top() += offset.y();
		BPoint origin = (initRect.bottomCenter() - area.pos()) * 100.0 / zoom;
		double ratio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, 1.0, ratio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Right)
	{
		BRect rect = initRect;
		rect.right() += offset.x();
		BPoint origin = (initRect.leftCenter() - area.pos()) * 100.0 / zoom;
		double ratio = (double)rect.width() / initRect.width();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, ratio, 1.0);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Bottom)
	{
		BRect rect = initRect;
		rect.bottom() += offset.y();
		BPoint origin = (initRect.topCenter() - area.pos()) * 100.0 / zoom;
		double ratio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, 1.0, ratio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_LeftTop)
	{
		BRect rect = initRect;
		rect.left() += offset.x();
		rect.top() += offset.y();
		BPoint origin = (initRect.rightBottom() - area.pos()) * 100.0 / zoom;
		double wratio = (double)rect.width() / initRect.width();
		double hRatio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_LeftBottom)
	{
		BRect rect = initRect;
		rect.left() += offset.x();
		rect.bottom() += offset.y();
		BPoint origin = (initRect.rightTop() - area.pos()) * 100.0 / zoom;
		double wratio = (double)rect.width() / initRect.width();
		double hRatio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_RightTop)
	{
		BRect rect = initRect;
		rect.right() += offset.x();
		rect.top() += offset.y();
		BPoint origin = (initRect.leftBottom() - area.pos()) * 100.0 / zoom;
		double wratio = (double)rect.width() / initRect.width();
		double hRatio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_RightBottom)
	{
		BRect rect = initRect;
		rect.right() += offset.x();
		rect.bottom() += offset.y();
		BPoint origin = (initRect.leftTop() - area.pos()) * 100.0 / zoom;
		double wratio = (double)rect.width() / initRect.width();
		double hRatio = (double)rect.height() / initRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _dragInitialRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
}

void LayerDragger::slotZoomChanged()
{
	_dirtySelection = true;
}
void LayerDragger::slotWidgetSelected(BObject* object, const BValue& value)
{
	_dirtySelection = true;
}

void LayerDragger::attached(BWidget* widget)
{
	_dirtySelection = true;
	connect(widget, "zoom-changed", &LayerDragger::slotZoomChanged);
	connect(widget, "widget-selected", &LayerDragger::slotWidgetSelected);
	Operation::attached(widget);
}
void LayerDragger::detached(BWidget* widget)
{
	disconnect(widget);
	Operation::detached(widget);
}

void LayerDragger::paint(BPainter& painter)
{
	PixmapArea* pixmapArea = this->pixmapArea();
	BRect area = pixmapArea->area();
	BPixmap* pixmap = pixmapArea->pixmap();

	if (_draging)
	{
		painter.setLineStipple(0x0F0F);
		painter.setColor(0, 200, 0);
		painter.drawRect(_dragRectMap[Part_None]);
		painter.setLineStipple(0);
	}
	else
	{
		painter.setColor(0, 200, 0);
		painter.drawRect(_dragRectMap[Part_None]);

	}
}

void LayerDragger::update(double time)
{

}
void LayerDragger::freshEvent(const BEvent& event)
{
	PixmapArea* pixmapArea = this->pixmapArea();
	if (_dirtySelection)
	{
		BRect area = pixmapArea->area();
		BWidgetSet& selectedWidgets = pixmapArea->selectedWidgets();
		if (selectedWidgets.size())
		{
			float ratio = pixmapArea->zoom() / 100.0f;
			BWidget* first = selectedWidgets.min();
			BRect rect = first->rect() * ratio + area.pos();
			for (int i = 1; i < selectedWidgets.size(); i++)
			{
				BWidget* layer = selectedWidgets[i];
				BRect layerRect = layer->rect() * ratio + area.pos();
				rect.expand(layerRect);
			}
			int b = 5;
			_dragRectMap[Part_None] = rect;
			_dragRectMap[Part_Left] = BRect(-b, b, b + b, rect.height() - b - b) + rect.pos();
			_dragRectMap[Part_Top] = BRect(b, -b, rect.width() - b - b, b + b) + rect.pos();
			_dragRectMap[Part_Right] = BRect(rect.width() - b, b, b + b, rect.height() - b - b) + rect.pos();
			_dragRectMap[Part_Bottom] = BRect(b, rect.height() - b, rect.width() - b - b, b + b) + rect.pos();
			_dragRectMap[Part_Center] = BRect(b, b, rect.width() - b - b, rect.height() - b - b) + rect.pos();
			_dragRectMap[Part_LeftTop] = BRect(-b, -b, b + b, b + b) + rect.pos();
			_dragRectMap[Part_LeftBottom] = BRect(-b, rect.height() - b, b + b, b + b) + rect.pos();
			_dragRectMap[Part_RightTop] = BRect(rect.width() - b, -b, b + b, b + b) + rect.pos();
			_dragRectMap[Part_RightBottom] = BRect(rect.width() - b, rect.height() - b, b + b, b + b) + rect.pos();
		}
		else
		{
			_dragRectMap.reset();
		}
		_dirtySelection = false;
	}
}

bool LayerDragger::focusEvent(const BEvent& event)
{
	return false;
}
bool LayerDragger::keyDownEvent(const BKeyEvent& keyEvent)
{
	return false;
}
bool LayerDragger::keyUpEvent(const BKeyEvent& keyEvent)
{
	return false;
}

bool LayerDragger::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	return false;
}
bool LayerDragger::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	return false;
}

bool LayerDragger::mousePressEvent(const BMouseEvent& mouseEvent)
{
	PixmapArea* pixmapArea = this->pixmapArea();
	if (mouseEvent.button() == Button_Left)
	{
		if (_dragPart)
		{
			_draging = true;
			_dragPoint = mouseEvent.pos();
			BWidgetSet& selectedWidgets = pixmapArea->selectedWidgets();
			_dragInitialRects.resize(selectedWidgets.size());
			for (int i = 0; i < selectedWidgets.size(); i++)
			{
				_dragInitialRects[i] = selectedWidgets[i]->rect();
			}
		}
		return true;
	}
	return false;
}
bool LayerDragger::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	PixmapArea* pixmapArea = this->pixmapArea();
	if (mouseEvent.button() == Button_Left)
	{
		if (_draging)
		{
			_draging = false;
			pixmapArea->setCursor(Cursor_None);
			if (mouseEvent.button() == Button_Left)
			{
				_dragPart = Part_None;
				_dragInitialRects.clear();
				_dirtySelection = true;
			}
		}
		return true;
	}
	return false;
}
bool LayerDragger::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	PixmapArea* pixmapArea = this->pixmapArea();
	if (_draging)
	{
		if (_dragPart && mouseEvent.button() == Button_Left)
		{
			applyPartDraging(pos);
			pixmapArea->fresh();
			return true;
		}
	}
	BRect area = pixmapArea->area();
	BPixmap* pixmap = pixmapArea->pixmap();
	float ratio = pixmapArea->zoom() / 100.0f;
	_dragPart = Part_None;
	for (auto it = _dragRectMap.begin(); it < _dragRectMap.end(); it++)
	{
		if (it.key() > Part_None && it->contain(pos))
		{
			_dragPart = it.key();
			break;
		}
	}
	if (_dragPart == Part_None)
		pixmapArea->setCursor(Cursor_None);
	else if (_dragPart == Part_Center)
		pixmapArea->setCursor(Cursor_SizeAll);
	else if (_dragPart == Part_Left || _dragPart == Part_Right)
		pixmapArea->setCursor(Cursor_SizeHor);
	else if (_dragPart == Part_Top || _dragPart == Part_Bottom)
		pixmapArea->setCursor(Cursor_SizeVer);
	else if (_dragPart == (Part_Left | Part_Top))
		pixmapArea->setCursor(Cursor_SizeLeftTop);
	else if (_dragPart == (Part_Left | Part_Bottom))
		pixmapArea->setCursor(Cursor_SizeLeftBottom);
	else if (_dragPart == (Part_Right | Part_Top))
		pixmapArea->setCursor(Cursor_SizeRightTop);
	else if (_dragPart == (Part_Right | Part_Bottom))
		pixmapArea->setCursor(Cursor_SizeRightBottom);

	return true;
}
bool LayerDragger::mouseWheelEvent(const BMouseEvent& mouseEvent)
{
	return false;
}
